package com.jgk.gwt.recipes.contacts.client.presenter;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.jgk.gwt.recipes.contacts.client.ContactsServiceAsync;
import com.jgk.gwt.recipes.contacts.client.event.AddContactEvent;
import com.jgk.gwt.recipes.contacts.client.event.EditContactEvent;
import com.jgk.gwt.recipes.contacts.shared.ContactDetails;

public class ContactsPresenter implements Presenter {
	private final ContactsServiceAsync rpcService;
	private final SimpleEventBus eventBus;
	private final Display display;
	private List<ContactDetails> contactDetails;

	  public interface Display {
		    HasClickHandlers getAddButton();
		    HasClickHandlers getDeleteButton();
		    HasClickHandlers getList();
		    void setData(List<String> data);
		    int getClickedRow(ClickEvent event);
		    List<Integer> getSelectedRows();
		    Widget asWidget();
		  }

	public ContactsPresenter(ContactsServiceAsync rpcService,
			SimpleEventBus eventBus, Display view) {
		this.rpcService = rpcService;
		this.eventBus = eventBus;
		this.display = view;
	}

	@Override
	public void go(final HasWidgets container) {
		Window.alert("it's go time ContactsPresenter");
		bind();
		container.clear();
		container.add(display.asWidget());
		fetchContactDetails();

	}

	public void bind() {
		display.getAddButton().addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				eventBus.fireEvent(new AddContactEvent());
			}
		});

		display.getDeleteButton().addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				deleteSelectedContacts();
			}
		});

		display.getList().addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				int selectedRow = display.getClickedRow(event);

				if (selectedRow >= 0) {
					String id = contactDetails.get(selectedRow).getId();
					eventBus.fireEvent(new EditContactEvent(id));
				}
			}
		});
	}

	  public void sortContactDetails() {
		    
		    // Yes, we could use a more optimized method of sorting, but the 
		    //  point is to create a test case that helps illustrate the higher
		    //  level concepts used when creating MVP-based applications. 
		    //
		    for (int i = 0; i < contactDetails.size(); ++i) {
		      for (int j = 0; j < contactDetails.size() - 1; ++j) {
		        if (contactDetails.get(j).getDisplayName().compareToIgnoreCase(contactDetails.get(j + 1).getDisplayName()) >= 0) {
		          ContactDetails tmp = contactDetails.get(j);
		          contactDetails.set(j, contactDetails.get(j + 1));
		          contactDetails.set(j + 1, tmp);
		        }
		      }
		    }
		  }

		  public void setContactDetails(List<ContactDetails> contactDetails) {
		    this.contactDetails = contactDetails;
		  }
		  
		  public ContactDetails getContactDetail(int index) {
		    return contactDetails.get(index);
		  }
		  
		  private void fetchContactDetails() {
		    rpcService.getContactDetails(new AsyncCallback<ArrayList<ContactDetails>>() {
		      public void onSuccess(ArrayList<ContactDetails> result) {
		          contactDetails = result;
		          sortContactDetails();
		          List<String> data = new ArrayList<String>();

		          for (int i = 0; i < result.size(); ++i) {
		            data.add(contactDetails.get(i).getDisplayName());
		          }
		          
		          display.setData(data);
		      }
		      
		      public void onFailure(Throwable caught) {
		        Window.alert("Error fetching contact details");
		      }
		    });
		  }

		  private void deleteSelectedContacts() {
		    List<Integer> selectedRows = display.getSelectedRows();
		    ArrayList<String> ids = new ArrayList<String>();
		    
		    for (int i = 0; i < selectedRows.size(); ++i) {
		      ids.add(contactDetails.get(selectedRows.get(i)).getId());
		    }
		    
		    rpcService.deleteContacts(ids, new AsyncCallback<ArrayList<ContactDetails>>() {
		      public void onSuccess(ArrayList<ContactDetails> result) {
		        contactDetails = result;
		        sortContactDetails();
		        List<String> data = new ArrayList<String>();

		        for (int i = 0; i < result.size(); ++i) {
		          data.add(contactDetails.get(i).getDisplayName());
		        }
		        
		        display.setData(data);
		        
		      }
		      
		      public void onFailure(Throwable caught) {
		        Window.alert("Error deleting selected contacts");
		      }
		    });
		  }
}
